#ifdef COMPILE_MAIN
#ifndef __DEBUG__
#define __DEBUG__
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hdi.h"
#include "filesystemdata.h"
#include "inode.h"
#include "filehandle.h"
#include "folder.h"
#include "path.h"
#include "minifilesystem.h"

#define TESTFUNC(f,...){\
	int ret;\
	ret = f(__VA_ARGS__);\
	if(ret){\
		printf(#f" returned %d\n",ret);\
	}\
}

#define TESTFUNC2(f,...){\
	int ret;\
	ret = f(__VA_ARGS__);\
	printf(#f"("#__VA_ARGS__")"" returned %d\n",ret);\
}

void print_hexn(char c){
	int i;
	for(i=7;i>=0;--i)
		printf("%d",(c&(1<<i))>>i);
	printf("\n");
}

void fs_d_rawDiskExplore(HardDriveInterface_t *hdi){
	char ask[80] = "A";
	while(strcmp(ask,"O")){
		gets(ask);
		if(!strcmp(ask,"O")) break;
		if(0>atoi(ask)) break;
		fs_d_print_block(hdi,atoi(ask));
	}
}


void debugBlockmap01(){
	char swap[1] = {0xff};int posInBlock;
	print_hexn(*swap);
	for(posInBlock=0;posInBlock<4;++posInBlock){
		swap[posInBlock/4]=(swap[posInBlock/4]&(~(0x03<<(posInBlock*2)%8)))
			|((1<<((posInBlock*2)%8))|(0<<((posInBlock*2+1)%8)));
		print_hexn(*swap);
	}
}

void debugBlockmap02(){
	HardDriveInterface_t hdi;
	FileSystemHandle_t fsh;
	uint32_t tc = 0;
	fs_newVirtualHDI(&hdi,1009,128);
	printf("fs_format() returned:%d\n",fs_format(&hdi));
	fs_openFileSystem(&hdi,&fsh);
	for(tc=0;tc<10;++tc){
		printf("is occuiped %d : %d\n",tc,fs_getIsBlockOccuiped(&fsh,tc));
	}
	tc=496;
	printf("is occuiped %d : %d\n",tc,fs_getIsBlockOccuiped(&fsh,tc));
	tc=497;
	printf("is occuiped %d : %d\n",tc,fs_getIsBlockOccuiped(&fsh,tc));
	fs_d_print_block(&hdi,5);
	fs_closeFileSystem(&fsh);
	fs_deleteVirtualHDI(&hdi);
}

void debugBlockmap03(){
	//Test if the blocks are set to occuiped and liberated correctly.
	HardDriveInterface_t hdi;
	FileSystemHandle_t fsh;
	int tc=496;
	fs_newVirtualHDI(&hdi,1009,128);
	printf("fs_format() returned:%d\n",fs_format(&hdi));
	fs_openFileSystem(&hdi,&fsh);
	printf("is occuiped %d : %d\n",tc,fs_getIsBlockOccuiped(&fsh,tc));
	printf("set occuiped %d returned %d\n",tc,fs_setBlockToOccuiped(&fsh,tc));
	printf("2nd set occuiped %d returned %d\n",tc,fs_setBlockToOccuiped(&fsh,tc));
	printf("is occuiped %d : %d\n",tc,fs_getIsBlockOccuiped(&fsh,tc));
	printf("free %d returned %d\n",tc,fs_freeBlock(&fsh,tc));
	printf("is occuiped %d : %d\n",tc,fs_getIsBlockOccuiped(&fsh,tc));
	//fs_d_print_block(hdi,2);
	fs_closeFileSystem(&fsh);
	fs_deleteVirtualHDI(&hdi);
}

void debugAllocInode01(){
	// Test the inode creation function.
	HardDriveInterface_t hdi;
	FileSystemHandle_t fsh;
	blockid_t whereItIs = 0;
	fs_newVirtualHDI(&hdi,1009,128);
	printf("fs_format() returned:%d\n",fs_format(&hdi));
	fs_openFileSystem(&hdi,&fsh);
	printf("newInode ret: %d",fs_newInode(&fsh,&whereItIs,false,true));
	printf(", in %d\n",whereItIs);
	fs_d_printFileInfo(&fsh,whereItIs);
	fs_closeFileSystem(&fsh);
	fs_deleteVirtualHDI(&hdi);
}
void debugFileHandleBasic(){
	HardDriveInterface_t hdi;
	FileSystemHandle_t fsh;
	blockid_t whereItIs = 0;
	filehandleid_t fileHandle;
	fs_newVirtualHDI(&hdi,1009,128);
	printf("fs_format() returned:%d\n",fs_format(&hdi));
	fs_openFileSystem(&hdi,&fsh);
	printf("newInode ret: %d",fs_newInode(&fsh,&whereItIs,false,true));
	printf(", in %d\n",whereItIs);
	fs_d_printFileInfo(&fsh,whereItIs);
	printf("newFileHandle ret: %d\n",fs_newFileHandle(&fsh, whereItIs, &fileHandle));
	printf("TestInode ret: %d\n",fs_inodeIsOpened(&fsh, whereItIs, &fileHandle));
	printf("deleteFileHandle ret: %d\n",fs_deleteFileHandle(&fsh, fileHandle));
	fs_closeFileSystem(&fsh);
	fs_deleteVirtualHDI(&hdi);
}
void debugFileHandleGetBlock(){
	HardDriveInterface_t hdi;
	FileSystemHandle_t fsh;
	blockid_t whereItIs = 0;
	//blockid_t blockNeeded;
	filehandleid_t fileHandle;
	fs_newVirtualHDI(&hdi,1009,128);
	printf("fs_format() returned:%d\n",fs_format(&hdi));
	fs_openFileSystem(&hdi,&fsh);
	printf("newInode ret: %d\n",fs_newInode(&fsh,&whereItIs,false,true));
	printf("newFileHandle ret: %d\n",fs_newFileHandle(&fsh, whereItIs, &fileHandle));
	printf("TestInode ret: %d\n",fs_inodeIsOpened(&fsh, whereItIs, &fileHandle));
	{
		unsigned char c='a';
		int i;
		for(i=0;i<10+32+65;++i){
			printf("Now i=%d\n",i);
			for(c=0;c<128;++c){
				if(fs_d_writeByte(&fsh,fileHandle,i*128+c,c)){
					return;
				}
			}
		}
	}
	fs_d_rawDiskExplore(&hdi);
	printf("deleteFileHandle ret: %d\n",fs_deleteFileHandle(&fsh, fileHandle));
	fs_closeFileSystem(&fsh);
	fs_deleteVirtualHDI(&hdi);
}

void debugSaveLoadHDI(){
	HardDriveInterface_t hdi;
	FileSystemHandle_t fsh;
	fs_newVirtualHDI(&hdi,1009,128);
	printf("fs_format() returned:%d\n",fs_format(&hdi));
	printf("fs_openFileSystem returned:%d\n",fs_openFileSystem(&hdi,&fsh));
	printf("fs_saveHDIToHardDrive returned:%d\n",fs_saveHDIToHardDrive(&hdi, "test.hdi"));
	fs_closeFileSystem(&fsh);
	fs_deleteVirtualHDI(&hdi);
	memset(&fsh, sizeof(fsh), 0);
	memset(&hdi, sizeof(hdi), 0);
	printf("fs_loadHDIFromHardDrive returned:%d\n",fs_loadHDIFromHardDrive(&hdi, "test.hdi"));
	fs_openFileSystem(&hdi,&fsh);
	fs_d_rawDiskExplore(&hdi);
	fs_closeFileSystem(&fsh);
	fs_deleteVirtualHDI(&hdi);
}

void debugWrite01(){
	HardDriveInterface_t hdi;
	FileSystemHandle_t fsh;
	char toWrite[] = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.\n";
	char toRead[1000];
	blockid_t whereItIs = 0;
	filehandleid_t fileHandle;
	fs_newVirtualHDI(&hdi,1009,100);
	printf("fs_format() returned:%d\n",fs_format(&hdi));
	fs_openFileSystem(&hdi,&fsh);
	printf("newInode ret: %d\n",fs_newInode(&fsh,&whereItIs,false,true));
	printf("newFileHandle ret: %d\n",fs_newFileHandle(&fsh, whereItIs, &fileHandle));
	{
		printf("write ret: %d\n",fs_write(&fsh,fileHandle,(byte_t*)toWrite,1));
		printf("write ret: %d\n",fs_write(&fsh,fileHandle,(byte_t*)toWrite,1));
		printf("write ret: %d\n",fs_write(&fsh,fileHandle,(byte_t*)toWrite,strlen(toWrite)+1));
		printf("deleteFileHandle ret: %d\n",fs_deleteFileHandle(&fsh, fileHandle));
		fs_d_printFileInfo(&fsh,whereItIs);
		fs_d_rawDiskExplore(&hdi);
		printf("newFileHandle ret: %d\n",fs_newFileHandle(&fsh, whereItIs, &fileHandle));
		printf("read ret: %d\n",fs_read(&fsh,fileHandle,(byte_t*)toRead,1));
		printf("read ret: %d\n",fs_read(&fsh,fileHandle,(byte_t*)toRead+1,1));
		printf("read ret: %d\n",fs_read(&fsh,fileHandle,(byte_t*)toRead+1+1,strlen(toWrite)+1));
		printf("%s",toRead);
	}
	printf("deleteFileHandle ret: %d\n",fs_deleteFileHandle(&fsh, fileHandle));
	fs_d_rawDiskExplore(&hdi);
	fs_closeFileSystem(&fsh);
	fs_deleteVirtualHDI(&hdi);
}

void debugFolderCreate01(){
	HardDriveInterface_t hdi;
	FileSystemHandle_t fsh;
	blockid_t whereItIs = 0;
	blockid_t whereItIs2 = 0;
	uint32_t blockCount = 0;
	TESTFUNC2(fs_newVirtualHDI,&hdi,1009,100)
	TESTFUNC(fs_format,&hdi)
	TESTFUNC(fs_openFileSystem,&hdi,&fsh)
	TESTFUNC(fs_createItemInFolder,&fsh,fsh.fsd.fsRoot,&whereItIs,"folder1",true)
	TESTFUNC(fs_createItemInFolder,&fsh,fsh.fsd.fsRoot,&whereItIs,"folder2",true)
	TESTFUNC(fs_diskUsage,&fsh, &blockCount)
	fs_diskUsage(&fsh, &blockCount);
	printf("$Current block count ret: %d\n",blockCount);
	printf("newItem ret: %d\n",fs_createItemInFolder(&fsh,whereItIs,&whereItIs2,"folder3",true));
	printf("newItem ret: %d\n",fs_createItemInFolder(&fsh,whereItIs,&whereItIs2,"folder4",true));
	{
		char *name = malloc(257);
		inodeid_t inodeid;
		filepos_t cursor = 0;
		fs_ret_t ret;/*
		while(!fs_getNextFolderItem(&fsh,fsh.fsd.fsRoot,&cursor,name,&inodeid)){
			printf("%d : \"%s\"\n",inodeid,name);
		}*/
		printf("fs_removeInodeFromFolder ret: %d\n",fs_removeInodeFromFolder(&fsh,fsh.fsd.fsRoot,whereItIs));
		cursor = 0;
		while(!(ret=fs_getNextFolderItem(&fsh,whereItIs,&cursor,name,&inodeid))){
			printf("%d : \"%s\"\n",inodeid,name);
		}
		printf("Ret was %d\n",ret);
		printf("delete folder ret: %d\n", fs_removeInodeRef(&fsh,fsh.fsd.fsRoot));
	}
	fs_diskUsage(&fsh, &blockCount);
	printf("$Current block count ret: %d\n",blockCount);
	fs_d_rawDiskExplore(&hdi);
	fs_closeFileSystem(&fsh);
	fs_deleteVirtualHDI(&hdi);
}

void dbgCutPathHead01(){
	char head[257];
	{
	char r[] = "Lool/D";
	printf("old path : %s\n",r);
	TESTFUNC(fs_cutPathHead,r,head);
	printf("main : \"%s\", head : \"%s\"\n",r,head);
	}{
	char r[] = "/Lool/D/../";
	printf("old path : %s\n",r);
	printf("Expected error.\n");
	TESTFUNC(fs_cutPathHead,r,head);
	}{
	char r[] = "/Lool/D/C/";
	printf("old path : %s\n",r);
	TESTFUNC(fs_cutPathHead,r,head);
	printf("main : \"%s\", head : \"%s\"\n",r,head);
	}{
	char r[] = "/c";
	printf("old path : %s\n",r);
	TESTFUNC(fs_cutPathHead,r,head);
	printf("main : \"%s\", head : \"%s\"\n",r,head);
	}{
	char r[] = "e";
	printf("old path : %s\n",r);
	TESTFUNC(fs_cutPathHead,r,head);
	printf("main : \"%s\", head : \"%s\"\n",r,head);
	}
}

void debugPath01(){

	HardDriveInterface_t hdi;
	FileSystemHandle_t fsh;
	blockid_t whereItIs = 0;
	blockid_t whereItIs2 = 0;
	uint32_t blockCount = 0;
	TESTFUNC2(fs_newVirtualHDI,&hdi,1009,100)
	TESTFUNC(fs_format,&hdi)
	TESTFUNC(fs_openFileSystem,&hdi,&fsh)
	TESTFUNC(fs_createItemInFolder,&fsh,fsh.fsd.fsRoot,&whereItIs,"folder1",true)
	TESTFUNC(fs_createItemInFolder,&fsh,fsh.fsd.fsRoot,&whereItIs,"folder2",true)
	TESTFUNC(fs_diskUsage,&fsh, &blockCount)
	fs_diskUsage(&fsh, &blockCount);
	printf("$Current block count ret: %d\n",blockCount);
	TESTFUNC(fs_createItemInFolder,&fsh,whereItIs,&whereItIs2,"folder3",true);
	TESTFUNC(fs_createItemInFolder,&fsh,whereItIs,&whereItIs2,"folder4",true);
	TESTFUNC(fs_createItemInFolder,&fsh,whereItIs2,&whereItIs2,"folder4",true);
	TESTFUNC(fs_getItemInFolderbyName,&fsh,whereItIs,"folder4",&whereItIs2);
	printf("f4 returned inode %d\n",whereItIs2);
	whereItIs2 = 0;
	TESTFUNC(fs_solvePath,&fsh,0,"/folder2/folder4/folder4/",NULL,&whereItIs2)
	printf("solvePath returned inode %d\n",whereItIs2);
	fs_d_rawDiskExplore(&hdi);
}
void minidebug01(){
	TESTFUNC(Minformat,100,1009);
	TESTFUNC(Minimkdir,"folder01");
	TESTFUNC(Minils);
	TESTFUNC(Minicd,"folder01");
	TESTFUNC(Minils);
	TESTFUNC(Minimkdir,"folder02");
	TESTFUNC(Minils);
	printf("Expect fail.\n");
	TESTFUNC(Minicd,"folder01");
	TESTFUNC(Minicd,"folder02");
	TESTFUNC(Minils);
	TESTFUNC(Minicd,"../../");
	TESTFUNC(Minils);
	TESTFUNC(Minimkdir,"folder01/folder03/");
	TESTFUNC(Minicd,"folder01");
	TESTFUNC(Minils);
	TESTFUNC(Minicd,"..");
	printf("Expect fail.\n");
	TESTFUNC(Minirm,"folder02");
	TESTFUNC(Minils);
	TESTFUNC(Minirm,"folder01");
	TESTFUNC(Minils);
	TESTFUNC(Miniclosefs);
}
void minidebugFile01(){
	char *toWrite = "chemeulemeuleu.";
	char toRead[200];
	int fd;
	TESTFUNC(Minformat,100,1009);
	TESTFUNC(Minimkdir,"folder01");
	printf("inodeId = %d.\n",fd = Miniopen("file1",FS_CREAT|FS_RDWR));
	TESTFUNC(Minils);
	printf("expect fail inode = %d.\n",Miniopen("folder01",FS_CREAT));
	TESTFUNC(Miniwrite,fd,toWrite,strlen(toWrite));
	TESTFUNC(Miniseek,fd,SEEK_SET,0);
	TESTFUNC(Miniread,fd,toRead,14);
	toRead[14] = '\0';
	printf("read \"%s\".\n",toRead);
	TESTFUNC(Miniclose,fd)
	TESTFUNC(Minicp,"file1","folder01/file2")
	TESTFUNC(Minicd,"folder01")
	TESTFUNC(Minils);
	printf("inodeId = %d.\n",fd = Miniopen("file2",FS_RDONLY));
	toRead[0] = '\0';
	TESTFUNC(Miniread,fd,toRead,14);
	toRead[14] = '\0';
	printf("read \"%s\".\n",toRead);
	TESTFUNC(Miniclose,fd)
	fs_d_rawDiskExplore(hdi);
	TESTFUNC(Miniclosefs);
}
void minidebugFile02(){
	int fd1,fd2;
	TESTFUNC(Minformat,100,1009);
	TESTFUNC(Minimkdir,"folder01");
	printf("inodeId = %d.\n",fd1 = Miniopen("file1",FS_CREAT|FS_RDWR));
	printf("inodeId = %d.\n",fd2 = Miniopen("file2",FS_CREAT|FS_RDWR));
	TESTFUNC(Miniclose,fd1)
	TESTFUNC(Miniclose,fd2)
	TESTFUNC(Miniclosefs);
}
void minidebugCp(){
	int fd;
	TESTFUNC(Minformat,100,1009);
	TESTFUNC(Minimkdir,"folder01");
	TESTFUNC(Minimkdir,"folder02");
	TESTFUNC(Minicd,"folder01")
	printf("inodeId = %d.\n",fd = Miniopen("file1",FS_CREAT|FS_RDWR));
	TESTFUNC(Miniclose,fd)
	TESTFUNC(Minimkdir,"folder03");
	TESTFUNC(Minicd,"..")
	TESTFUNC(Minicp,"folder01","folder02/folder01cp")
	TESTFUNC(Minicd,"folder02")
	TESTFUNC(Minils);
	TESTFUNC(Minicd,"folder01cp")
	TESTFUNC(Minils);
	fs_d_rawDiskExplore(hdi);
	TESTFUNC(Miniclosefs);
}
int main()
{
	printf("------------------------\n");
	printf("Compiled the %s at %s.\n",__DATE__,__TIME__);
	printf("Debug Code\n");
	printf("------------------------\n\n");
	//printf("%d",sizeof(inode_t));
	minidebugFile02();
	printf("Test Over.\n");
	getchar();
	return 0;
}
#endif
